#pragma once

#include <cftc/typecontainer/list.h>

namespace game::system::grid {

    // forward declaration
    template<class A, class T, class O> class GridLoader;

    template <typename ACTIVE_OBJECT, typename WORLD_CONTAINER, typename GRID_CONTAINER>
    class Grid
    {
        // allows the GridLoader to access its internals
        template<class A, class T, class O> friend class GridLoader;

    public:

        template<class SPECIFIC_OBJECT>
        /**
         * @brief an object of interested enters the grid
         *
         * @param obj
         * @return bool
         */
        bool AddWorldObject(SPECIFIC_OBJECT* obj)
        {
#if 1
            return true;
#else
            return i_worldContainer.template insert<SPECIFIC_OBJECT>(obj);
#endif
        }

        template<class SPECIFIC_OBJECT>
        /**
         * @brief an object of interested exits the grid
         *
         * @param obj
         * @return bool
         */
        bool RemoveWorldObject(SPECIFIC_OBJECT* obj)
        {
#if 1
            return true;
#else
            return i_worldContainer.template remove<SPECIFIC_OBJECT>(obj);
#endif
        }

        template<class SPECIFIC_OBJECT>
        /**
         * @brief Inserts a container type object into the grid.
         *
         * @param obj
         * @return bool
         */
        bool AddGridObject(SPECIFIC_OBJECT* obj)
        {
#if 1
            return true;
#else
            if (obj->IsActiveObject())
            {
                m_activeGridObjects.insert(obj);
            }

            return i_gridContainer.template insert<SPECIFIC_OBJECT>(obj);
#endif
        }

        template<class SPECIFIC_OBJECT>
        /**
         * @brief Removes a container type object from the grid
         *
         * @param obj
         * @return bool
         */
        bool RemoveGridObject(SPECIFIC_OBJECT* obj)
        {
#if 1
            return true;
#else
            if (obj->IsActiveObject())
            {
                m_activeGridObjects.erase(obj);
            }

            return i_gridContainer.template remove<SPECIFIC_OBJECT>(obj);
#endif
        }

#if 0
        template<class T>
        void Visit(TypeContainerVisitor<T, GRID_CONTAINER>& visitor)
        {
#if 0
            visitor.Visit(i_gridContainer);
#endif
        }

        template<class T>
        void Visit(TypeContainerVisitor<T, WORLD_CONTAINER>& visitor)
        {
#if 0
            visitor.Visit(i_worldContainer);
#endif
        }

        size_t ActiveObjectsInGrid() const
        {
#if 1
            return 0;
#else
            return m_activeGridObjects.size() + i_worldContainer.template count<ACTIVE_OBJECT>(nullptr);
#endif
        }
#endif
        GRID_CONTAINER& GetGridContainer() { return i_gridContainer; }
        WORLD_CONTAINER& GetWorldContainer() { return i_worldContainer; }
    private:
        GRID_CONTAINER  i_gridContainer;
        WORLD_CONTAINER i_worldContainer;
        std::set<void*> m_activeGridObjects;
    };

}